
var layerList = [];
var activeLayerID = 0;
var canvasWidth = canvasHeight = 640;
var previewCanvasWidth = previewCanvasHeight = 64;
var gridWidth = 32;
var gridHeight = 32;
var pixelSize;
var previewPixelSize;

// fps and counter stuff
var fps = 200;
var interval = Math.round(1000/fps);
var fpsCounter = 0, now, lastUpdate = (new Date)*1 - 1;
var fpsFilter = 50;

var colorPicker;
var activeColor = '#ffffff';
var takeColorPicker = true;
var recentColorArray;
var colorBoxCount = 0;
var gridToggle = true;

var deleteChosen = false;
var pipetteChosen = false;

function init() {
	//canvas = document.getElementById('canvas'+layerList.length);
	colorPicker = document.getElementById('colorpicker');
	recentColorArray = $$('.recentColorBox');
	//ctx = canvas.getContext('2d');
	pctx = $('previewCanvas').getContext('2d');
	
	setupEditor();
	
	setInterval(loop, interval);
	
	// FPS drawing:
	var fpsOut = document.getElementById('fpsCount');
	setInterval(function(){
	  fpsOut.innerHTML = fps.toFixed(1) + "fps";
	}, 1000);
	
	// add eventlisteners to the recent color boxes:
	$('recentColorChooser').observe('click', retrieveColor);
	// add eventlistener to the resolution select:
	$('resSelect').observe('change', changeResolution);
	// add eventlistener to the toolBoxes:
	$('toolBoxes').observe('click', chooseTool);
	
	// add eventlisteners to the JSON areas
	var divs = $$('.hiddenContainer');
	for(var i = 0; i < divs.length; i++) {
		divs[i].observe('click', function(e) {
			var div = e.findElement('div');
			if(div.down('.hidden')) {
				if(div.down('.hidden').getStyle('display') === 'none') {
					div.down().setStyle({
						display: 'block'
					});
				} else {
					div.down('.hidden').setStyle({
						display: 'none'
					});
				}
			}
		});
	}
	
}

function setupEditor() {
	previewPixelSize = Math.round($('previewCanvas').width / gridWidth);
	pixelSize = canvasWidth / gridWidth;
	
	// create the first layer
	createLayer();
	createPreview();
	
	$('layerID').innerHTML = (activeLayerID + 1) +  '/' + layerList.length;
}

function changeResolution(value) {
	gridWidth = gridHeight = parseInt($('resSelect').getValue());
	setupEditor();
}

function loop() {
	drawLayers();
	drawPreview();
	
	// frame counting
	var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
	fpsCounter += (thisFrameFPS - fpsCounter) / fpsFilter;
	lastUpdate = now * 1 - 1;
	//setTimeout(drawFrame, 1);
	
	activeColor = colorPicker.style.backgroundColor;
}

function drawLayers() {
	for(var k = 0; k < layerList.length; k++) {
		var grid = layerList[k].getGrid();
		var ctx = layerList[k].getCanvas().getContext('2d');
		ctx.clearRect(0, 0, canvasWidth, canvasHeight);
		for(var i = 0; i  < grid.length; i++) {
			for(var j = 0; j < grid[i].length; j++) {
				grid[i][j].draw(ctx);
			}
		}
	}
}

function drawPreview() {
	var pctx2 = $('previewCanvas').getContext('2d');
	pctx2.clearRect(0 , 0, previewCanvasWidth, previewCanvasHeight);
	
	for(var k = 0; k < layerList.length; k++) {
		var grid = layerList[k].getGrid();
		var pctx = $('previewCanvas'+k).getContext('2d');
		pctx.clearRect(0 , 0, previewCanvasWidth, previewCanvasHeight);
		
		// mark preview canvas as active
		if(k == activeLayerID) {
			$('previewCanvas'+k).style.borderColor = '#FF511C';
		} else {
			$('previewCanvas'+k).style.borderColor = '#000000';
		}
		
		// draw preview canvases
		for(var i = 0; i  < grid.length; i++) {
			for(var j = 0; j < grid[i].length; j++) {
				if(grid[i][j].colorSet) {
					pctx.fillStyle = grid[i][j].fillColor;
					pctx.fillRect(j * previewPixelSize, i * previewPixelSize, previewPixelSize, previewPixelSize);
					if(k == activeLayerID) {
						pctx2.fillStyle = grid[i][j].fillColor;
						pctx2.fillRect(j * previewPixelSize, i * previewPixelSize, previewPixelSize, previewPixelSize);
						$('debug').innerHTML = 'tada';
					}
				}
			}
		}
	}
}

function toggleDrawGrid() {
	gridToggle = !gridToggle;
	layerList[activeLayerID].toggleGrid(gridToggle);
}

function setTakePicker() {
	takeColorPicker = true;
}

function retrieveColor(e) {
	var div = e.findElement('div');
	if(div) {
		if(div.getStyle('backgroundColor')) {
			activeColor = div.getStyle('backgroundColor');
			$$('.color')[0].setValue(rgbToHex(activeColor));
			$$('.color')[0].dispatchEvent(keyboardEvent);
			takeColorPicker = false;
		}
	}
}

function updateRecentColors() {
	var found = false;
	for(var i = 0; i < recentColorArray.length; i++) {
		if(recentColorArray[i].getStyle('backgroundColor') == activeColor)
			return;
	}
	if(!found) {
		recentColorArray[colorBoxCount].setStyle({
			backgroundColor: activeColor
		});
		if(colorBoxCount < recentColorArray.length - 1)
			colorBoxCount++;
	}
}

function chooseTool(e) {
	var div = e.findElement('div');
	if(div) {
		if(div.id === 'delete') {
			if(deleteChosen) {
				deleteChosen = false;
				div.setStyle({
					backgroundColor: ''
				});
			} else {
				div.setStyle({
					backgroundColor: '#FFEA29'
				});
				$('pipette').setStyle({
					backgroundColor: ''
				});	
				deleteChosen = true;
				pipetteChosen = false;
			}
		} else if(div.id === 'pipette') {
			if(pipetteChosen) {
				div.setStyle({
					backgroundColor: ''
				});
				pipetteChosen = false;
			} else {
				div.setStyle({
					backgroundColor: '#FFEA29'
				});
				$('delete').setStyle({
					backgroundColor: ''
				});	
				pipetteChosen = true;
				deleteChosen = false;
			}
		}
	}
}

function saveToJSON() {
	var grid = layerList[activeLayerID].getGrid();
	var text = JSON.stringify(grid);
	$('jsonOutputArea').value = text;
}

function loadJSON() {
	var text = $('jsonInputArea').value;
	//alert(text);
	var jsonArray = JSON.parse(text);
	
	for(var i = 0; i < jsonArray.length; i++) {
		for(var j = 0; j < jsonArray[i].length; j++) {
			var seg = new Segment();
			//jsonArray[i].prototype = seg.prototype;
			jsonArray[i][j].draw = seg.draw;
			jsonArray[i][j].setColor = seg.setColor;
			jsonArray[i][j].drawGrid = seg.drawGrid;
		}
	}
	grid = jsonArray;
}

function saveToPNG() {
	
	var fileName = $('ssFilenameInput').value;
	if(fileName == '') {
		alert('Please enter a filename!');
	} else {			
		$('ssCanvas').toBlob(function(blob) {
			saveAs(blob, (fileName) + ".png");
		}, "image/png");
		
		closeSpriteSheetWindow();
	}
}

/*
 * prototype for the individual segments on the editor
 */
function Segment(i, j, x, y, width, height) {
	this.i = i;
	this.j = j;
	this.x = x;
	this.y = y;
	this.width = width;
	this.height = height;
	this.drawGrid = true;
	this.colorSet = false;
	
	this.fillColor = '#ffffff';
	this.fillBorder = '#333333';
}

Segment.prototype = {

	draw: function(ctx) {
		ctx.fillStyle = this.fillColor;
		
		if(this.colorSet)
			ctx.fillRect(this.x, this.y, this.width, this.height);
		else 
			ctx.clearRect(this.x, this.y, this.width, this.height);
		
		if(this.drawGrid) {
			ctx.lineWidth = 1;
			ctx.strokeRect(this.x, this.y, this.width, this.height);
		}
	},
	
	setColor: function(color) {
		if(deleteChosen) {
			this.colorSet = false;
		} else if(pipetteChosen) {
			if(this.colorSet) {
				activeColor = this.fillColor;
				$$('.color')[0].setValue(rgbToHex(this.fillColor));
				$$('.color')[0].dispatchEvent(keyboardEvent);
			}
		} else {
			this.fillColor = color;
			this.colorSet = true;
		}
	},
	
	toggleGrid: function(drawGrid){
		this.drawGrid = drawGrid;
	}
}

function Layer() {
	var grid;
	var layerID;
	var canvas;
	
	// create the DOM element for this layer
	var tmpCanvas = document.createElement('canvas');
	tmpCanvas.setAttribute('id', 'canvas'+layerList.length);
	tmpCanvas.setAttribute('class', 'canvasLayer');
	tmpCanvas.setAttribute('width', canvasWidth);
	tmpCanvas.setAttribute('height', canvasHeight);
	$('canvasDiv').appendChild(tmpCanvas);
	this.canvas = tmpCanvas;
}

Layer.prototype = {
	setGrid: function(grid) {
		this.grid = grid;
	},
	
	getGrid: function() {
		return this.grid;
	},
	
	setID: function(id) {
		this.layerID = id;
	},
	
	getID: function() {
		return this.layerID;
	},
	
	getCanvas: function() {
		return this.canvas;
	},
	
	setToBackground: function() {
		this.canvas.setStyle({
			opacity: 0.3
		});
		this.toggleGrid(false);
	},
	
	setToForeground: function() {
		this.canvas.setStyle({
			opacity: 1.0
		});
		this.toggleGrid(true);
	},
	
	toggleGrid: function(gridVal) {
		for(var i = 0; i < this.grid.length; i++) {
			for(var j = 0; j < this.grid[i].length; j++) {
				this.grid[i][j].toggleGrid(gridVal);
			}
		}
	},
}

function addLayer() {
	createLayer();
	
	layerList[activeLayerID].setToBackground();
	activeLayerID += 1;
	createPreview();
	InputHandler.setObserveCanvas();
	
	$('layerID').innerHTML = (activeLayerID + 1) + '/' + layerList.length;
}

function removeLayer() {
	if(layerList.length > 1) {
		$('canvasDiv').removeChild($('canvas' + (layerList.length-1)));
		$('previewRow').removeChild($('previewCanvas' + (layerList.length-1)));
		
		layerList.splice(layerList.length - 1, 1);
		activeLayerID -= 1;
		
		layerList[activeLayerID].setToForeground();
		
		InputHandler.setObserveCanvas();
		$('layerID').innerHTML = (activeLayerID + 1) + '/' + layerList.length;
	}
}

function nextLayer() {
	layerList[activeLayerID].setToBackground();
	
	if(activeLayerID < layerList.length - 1)
		activeLayerID += 1;
	else 
		activeLayerID = 0;
		
	layerList[activeLayerID].setToForeground();
	
	$('layerID').innerHTML = (activeLayerID + 1) + '/' + layerList.length;
}

function prevLayer() {
	layerList[activeLayerID].setToBackground();

	if(activeLayerID > 0)
		activeLayerID -= 1;
	else 
		activeLayerID = layerList.length - 1;
		
	layerList[activeLayerID].setToForeground();
	
	$('layerID').innerHTML = (activeLayerID + 1)+ '/' + layerList.length;
}

function createLayer() {
	var layer = new Layer();
	var grid;
	
	// create the grid for the editor
	grid = new Array(gridHeight);
	for(var i = 0; i < grid.length; i++) {
		grid[i] = new Array(gridWidth);
	}
	
	// fills it with Segments
	if($('keepPicture').checked && layerList.length != 0) {
		var oldGrid = layerList[activeLayerID].getGrid();
		for(var i = 0; i < grid.length; i++) {
			for(var j = 0; j < grid[i].length; j++) {
				grid[i][j] = new Segment(i, j, j*pixelSize, i*pixelSize, gridWidth, gridHeight);
				if(oldGrid[i][j].colorSet)
					grid[i][j].setColor(oldGrid[i][j].fillColor);
			}
		}
	} else {
		for(var i = 0; i < grid.length; i++) {
			for(var j = 0; j < grid[i].length; j++) {
				grid[i][j] = new Segment(i, j, j*pixelSize, i*pixelSize, gridWidth, gridHeight);
			}
		}
	}
	
	layer.setID(layerList.length);
	layer.setGrid(grid);
	
	layerList.push(layer);
	layer.setToForeground();
	InputHandler.setObserveCanvas();
}

function createPreview() {
	var tmpCanvas = document.createElement('canvas');
	tmpCanvas.setAttribute('id', 'previewCanvas' + (layerList.length-1));
	tmpCanvas.setAttribute('class', 'previewCanvas');
	tmpCanvas.setAttribute('width', previewCanvasWidth);
	tmpCanvas.setAttribute('height', previewCanvasHeight);
	$('previewRow').appendChild(tmpCanvas);
}

function createSpriteSheetWindow() {
	// create the window
	var tmpWindow = document.createElement('div');
	tmpWindow.setAttribute('id', 'spriteSheetWindow');
	
	// create the buttons
	var cancelButton = document.createElement('input');
	cancelButton.setAttribute('value', 'Cancel');
	cancelButton.setAttribute('type', 'button');
	cancelButton.setAttribute('onClick', 'closeSpriteSheetWindow();');
	
	var saveButton = document.createElement('input');
	saveButton.setAttribute('value', 'Save');
	saveButton.setAttribute('type', 'button');
	saveButton.setAttribute('onClick', 'saveToPNG()');
	
	// create the filename input
	var filenameInput = document.createElement('input');
	filenameInput.setAttribute('id', 'ssFilenameInput');
	
	// create the button div
	var buttonDiv = document.createElement('div');
	buttonDiv.setAttribute('id', 'ssButtonDiv');
	// create the canvas div
	var canvasDiv = document.createElement('div');
	canvasDiv.setAttribute('id', 'ssCanvasDiv');
	
	// create the canvas
	
	// calculate the width and height of the canvas based on the layers
	var cols = 0;
	var rows = 0;
	var maxCols = 8;
	for(var i = 0; i < layerList.length; i++) {
		if(cols < maxCols)
			cols++;
		if(i % maxCols === 0)
			rows++;
	}
	var width = previewCanvasWidth * cols;
	var height = previewCanvasWidth * rows;
	
	// setup the canvas
	var tmpCanvas = document.createElement('canvas');
	tmpCanvas.setAttribute('id', 'ssCanvas');
	tmpCanvas.setAttribute('width', width);
	tmpCanvas.setAttribute('height', height);
	
	var pctx = $(tmpCanvas).getContext('2d');
	pctx.clearRect(0 , 0, width, height);
	
	var xOffset = 0;
	var yOffset = 0;
	for(var k = 0; k < layerList.length; k++) {
		var grid = layerList[k].getGrid();
		// draw preview canvases
		for(var i = 0; i  < grid.length; i++) {
			for(var j = 0; j < grid[i].length; j++) {
				if(grid[i][j].colorSet) {
					pctx.fillStyle = grid[i][j].fillColor;
					pctx.fillRect(j * previewPixelSize + xOffset
								, i * previewPixelSize + yOffset
								, previewPixelSize, previewPixelSize
					);
				}
			}
		}
		xOffset += previewCanvasWidth;
		if(xOffset >= previewCanvasWidth * 8) {
			xOffset = 0;
			yOffset += previewCanvasHeight;
		}
	}
	
	
	// put it all together
	$(canvasDiv).appendChild(tmpCanvas);
	$(buttonDiv).appendChild(saveButton);
	$(buttonDiv).appendChild(cancelButton);
	
	$(tmpWindow).appendChild(canvasDiv);
	$(tmpWindow).appendChild(filenameInput);
	$(tmpWindow).appendChild(buttonDiv);
	
	$('main').appendChild(tmpWindow);
	
}

function closeSpriteSheetWindow() {
	//document.getElementByID('main').removeChild('spriteSheetWindow');
	$('spriteSheetWindow').remove();
}

var InputHandler = {
	activeCanvas : 0,
	/*
	 * Mouse properties
	 */
	mouse : {
		left : 0,
		right : 0,
		pressed : false,
		dragged : false
	},
	
	/*
	 * mouse grid position
	 */
	gridpos : {
		x : 0,
		y : 0
	},	

	/*
	 * mouse position
	 */
	mouseposition : {
		x : 0,
		y : 0
	},
	
	/*
	 * Initialize bindings
	 * adapted from http://code.google.com/p/cartagen/source/browse/branches/0.6/cartagen/public/cartagen/src/glop/events.js?r=336
	 */
	
	setObserveCanvas: function() {
		if(this.activeCanvas) {
			this.activeCanvas.stopObserving('contextmenu', function(e) { e.stop(); });
			this.activeCanvas.stopObserving('mousemove', InputHandler.onMouseMoved);
			this.activeCanvas.stopObserving('mousedown', InputHandler.onMousePressed);
			this.activeCanvas.stopObserving('mouseup', InputHandler.onMouseReleased);
		}
		this.activeCanvas = $('canvas'+activeLayerID);
		
		this.activeCanvas.observe('contextmenu', function(e) { e.stop(); });
		this.activeCanvas.observe('mousemove', InputHandler.onMouseMoved);
		this.activeCanvas.observe('mousedown', InputHandler.onMousePressed);
		this.activeCanvas.observe('mouseup', InputHandler.onMouseReleased);
		
		
	},
	
	/*
	 * handle mouse movement
	 */
	onMouseMoved: function(e) {
		InputHandler.setCursorPos(e);
		
		if(InputHandler.mouse.pressed) {
			InputHandler.mouse.dragged = true;
			if(InputHandler.mouse.left) {
				layerList[activeLayerID].getGrid()[InputHandler.gridpos.y][InputHandler.gridpos.x].setColor(activeColor);
				updateRecentColors();
			} 
		}
	},
	
	/*
	 * register left/right mouse button down
	 */
	onMousePressed: function(e) {
		if(InputHandler.isRightButtonClicked(e)) {
			InputHandler.mouse.right = 1
		} else {
			InputHandler.mouse.left = 1
		}
		InputHandler.mouse.pressed = true;
		InputHandler.mouse.dragged = false;
	},
	
	/*
	 * register left/right mouse button up, calling click function
	 */
	onMouseReleased: function(e) {
		if(InputHandler.isRightButtonClicked(e) && InputHandler.mouse.right == 1) {
			InputHandler.handleRightClick(e);
		} else if(InputHandler.mouse.left == 1) {
			InputHandler.handleLeftClick(e);
		}
		InputHandler.mouse.right = 0;
		InputHandler.mouse.left = 0;
		InputHandler.mouse.pressed = false;
	},
	
	/*
	 * called in onmousemove to update the current cursor position
	 */
	setCursorPos: function(e) {
		// calculate the mouse position on the canvas
		InputHandler.mouseposition.x = e.clientX - this.activeCanvas.offsetLeft;
		InputHandler.mouseposition.y = e.clientY - this.activeCanvas.offsetTop;
		
		// calculate the mouse position in the grid
		var x = Math.floor(InputHandler.mouseposition.x / pixelSize);
		var y = Math.floor(InputHandler.mouseposition.y / pixelSize);
		if(y >= 0 && y < gridHeight) {
			InputHandler.gridpos.y = y;
		}
		if(x >= 0 && x < gridWidth) {
			InputHandler.gridpos.x = x;
		}
		//debug.innerHTML = gridWidth + ' ' + gridHeight + ' ' + InputHandler.gridpos.x + ' ' + InputHandler.gridpos.y;
	},

	/*
	 * helper function to check whether the right mouse button was pressed
	 */
	isRightButtonClicked: function(e) { 
		var rightclick = false;
		e = e || window.event;
		if(e.which)
			rightclick = (e.which == 3);
		else if(e.button)
			rightclick = (e.button == 2);
			
		return rightclick;
	},
	
	
	
	/*
	 * handles everything related to the right mouse button
	 */
	handleRightClick: function(e) {
	
	},

	/*
	 * handles everything related to the left mouse button
	 */
	handleLeftClick: function(e) {
		var xPos = InputHandler.gridpos.x;
		var yPos = InputHandler.gridpos.y;
		var grid = layerList[activeLayerID].getGrid();
		grid[yPos][xPos].setColor(activeColor);
		updateRecentColors();
	}
}

